/*
 *      Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: Chill 庄骞 (smallchill@163.com)
 */
package org.springblade.modules.system.service.impl.cuser;


import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.lang.Assert;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import jakarta.annotation.Resource;
import org.springblade.common.cache.SysCache;
import org.springblade.core.log.exception.ServiceException;
import org.springblade.core.mp.support.Condition;
import org.springblade.core.secure.utils.AuthUtil;
import org.springblade.core.tool.constant.BladeConstant;
import org.springblade.core.tool.support.Kv;
import org.springblade.core.tool.utils.*;
import org.springblade.modules.auth.dto.*;
import org.springblade.modules.auth.enums.UserEnum;
import org.springblade.modules.auth.provider.UserType;
import org.springblade.modules.auth.utils.TokenUtil;
import org.springblade.modules.sms.AliSmsTemplate;
import org.springblade.modules.sms.model.SmsCode;
import org.springblade.modules.system.mapper.cuser.AgentUserMapper;
import org.springblade.modules.system.pojo.entity.*;
import org.springblade.modules.system.pojo.entity.cuser.AgentUser;
import org.springblade.modules.system.service.IAgentUserService;
import org.springblade.modules.system.service.IUserOauthService;
import org.springblade.modules.system.service.impl.idcardauth.AliIdCardAuthServiceImpl;
import org.springblade.modules.system.service.impl.idcardauth.IdCardAuthComponent;
import org.springblade.modules.system.utils.DataMaskingUtil;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.text.SimpleDateFormat;
import java.util.*;

/**
 * 服务实现类
 *
 * @author Chill
 */
@Service
public class AgentUserServiceImpl extends ServiceImpl<AgentUserMapper, AgentUser> implements IAgentUserService {

    private static final String GUEST_NAME = "guest";

    @Resource
    private IUserOauthService userOauthService;

    @Resource
    private AliSmsTemplate aliSmsTemplate;

    @Resource
    private IdCardAuthComponent idCardAuthComponent;

    @Override
    public UserInfo userInfo(String tenantId, String account, String password, UserEnum userEnum) {
        AgentUser user =new AgentUser();
        user.setTenantId(tenantId);
        user.setAccount(account);
        user.setPassword(password);
        AgentUser queryUser = baseMapper.selectOne(new QueryWrapper<>(user));
        return buildUserInfo(queryUser, userEnum);
    }

    @Override
    public UserInfo userInfo(String tenantId, String phone, UserEnum userEnum) {
        AgentUser user =new AgentUser();
        user.setTenantId(tenantId);
        user.setUserPhone(phone);
        user.setUserType(2);
        AgentUser queryUser = baseMapper.selectOne(new QueryWrapper<>(user));
        return buildUserInfo(queryUser, userEnum);
    }

    @Override
    public UserInfo userInfo(Long userId) {
        AgentUser user = baseMapper.selectById(userId);
        return buildUserInfo(user);
    }

    @Override
    public UserInfo userInfo(Long userId, UserEnum userEnum) {
        AgentUser user = baseMapper.selectById(userId);
        return buildUserInfo(user, userEnum);
    }

    private UserInfo buildUserInfo(AgentUser user) {
        return buildUserInfo(user, UserEnum.WEB);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public UserInfo userInfo(UserOauth userOauth) {
        UserOauth uo = userOauthService.getOne(Wrappers.<UserOauth>query().lambda().eq(UserOauth::getUuid, userOauth.getUuid()).eq(UserOauth::getSource, userOauth.getSource()));
        UserInfo userInfo;
        if (Func.isNotEmpty(uo) && Func.isNotEmpty(uo.getUserId())) {
            userInfo = this.userInfo(uo.getUserId());
            userInfo.setOauthId(Func.toStr(uo.getId()));
        } else {
            userInfo = new UserInfo();
            if (Func.isEmpty(uo)) {
                userOauthService.save(userOauth);
                userInfo.setOauthId(Func.toStr(userOauth.getId()));
            } else {
                userInfo.setOauthId(Func.toStr(uo.getId()));
            }
            AgentUser user = new AgentUser();
            user.setAccount(userOauth.getUsername());
            user.setTenantId(userOauth.getTenantId());
            userInfo.setAgentUser(user);
            userInfo.setRoles(Collections.singletonList(GUEST_NAME));
        }
        return userInfo;
    }

    private UserInfo buildUserInfo(AgentUser user, UserEnum userEnum) {
        if (ObjectUtil.isEmpty(user)) {
            return null;
        }
        String userTypeCheck = Objects.isNull(user.getUserType()) || user.getUserType().equals(1) ? "用户不存在!" : null;
        if (StringUtil.isNotBlank(userTypeCheck)) {
            throw new ServiceException(userTypeCheck);
        };

        UserInfo userInfo = new UserInfo();
        userInfo.setAgentUser(user);
        // 根据每个用户平台，建立对应的detail表，通过查询将结果集写入到detail字段
        Kv detail = Kv.create().set("type", userEnum.getName());
        if (userEnum == UserEnum.WEB) {
            UserWeb userWeb = new UserWeb();
            UserWeb query = userWeb.selectOne(Wrappers.<UserWeb>lambdaQuery().eq(UserWeb::getUserId, user.getId()));
            if (ObjectUtil.isNotEmpty(query)) {
                detail.set("ext", query.getUserExt());
            }
        } else if (userEnum == UserEnum.APP) {
            UserApp userApp = new UserApp();
            UserApp query = userApp.selectOne(Wrappers.<UserApp>lambdaQuery().eq(UserApp::getUserId, user.getId()));
            if (ObjectUtil.isNotEmpty(query)) {
                detail.set("ext", query.getUserExt());
            }
        } else {
//			UserOther userOther = new UserOther();
//			UserOther query = userOther.selectOne(Wrappers.<UserOther>lambdaQuery().eq(UserOther::getUserId, user.getId()));
//			if (ObjectUtil.isNotEmpty(query)) {
//				detail.set("ext", query.getUserExt());
//			}
        }
        userInfo.setDetail(detail);
        return userInfo;
    }

    @Override
    public Kv registerGuest(UserRegisterDTO dto) {
        // 验证两次密码是否正确
        if (!dto.getFisPassword().equals(dto.getSecPassword())) {
            throw new ServiceException("两次密码不一致!");
        }

        // 验证租户加手机号是否重复
        AgentUser selectOne = baseMapper.selectOne(Wrappers.<AgentUser>query().lambda()
                .eq(AgentUser::getTenantId, dto.getTenantId())
                .eq(AgentUser::getUserType, 2)
                .eq(AgentUser::getUserPhone, dto.getUserPhone())
                .eq(AgentUser::getIsDeleted, BladeConstant.DB_NOT_DELETED));
        if (Objects.nonNull(selectOne)) {
            throw new ServiceException("用户已存在,请直接登录!");
        }

        // 验证通过销售分享注册还是邀请注册
//        if (StringUtil.isEmpty(dto.getInviteCode()) && StringUtil.isEmpty(dto.getSalesUserId())) {
//            throw new ServiceException("非分享渠道注册，不可注册!");
//        }

        // 上正式放开，验证验证码是否正确
        SmsCode smsCode = new SmsCode();
        smsCode.setId(dto.getSmsKey());
        smsCode.setPhone(dto.getUserPhone());
        smsCode.setValue(dto.getSmsValue());
        // 短信验证默认通过，等短信开通后配合短信发送一起放开
        boolean valid = aliSmsTemplate.validateMessage(smsCode);
        if (!valid) {
            throw new ServiceException("短信验证码错误");
        }

//		if (!"8888".equals(dto.getSmsValue())) {
//			throw new ServiceException("短信验证码错误");
//		}

        // 构建用户信息并保存
        AgentUser agentUser = BeanUtil.toBean(dto, AgentUser.class);
        agentUser.setUserType(2);
        agentUser.setPassword(DigestUtil.hex(dto.getFisPassword()));
        agentUser.setUuId(this.getUuid());
        agentUser.setAccount(dto.getUserPhone());
        agentUser.setUserName(dto.getUserPhone());
        agentUser.setRealNameState(0);
        agentUser.setMemberState(0);
        agentUser.setFollowState(0);
        agentUser.setEnableState(1);
        agentUser.setRecentLoginTime(cn.hutool.core.date.DateUtil.date());
        agentUser.setCreateTime(cn.hutool.core.date.DateUtil.date());
        agentUser.setUpdateTime(cn.hutool.core.date.DateUtil.date());
        agentUser.setGradeLabel(0);
        agentUser.setIsDeleted(0);
        // 保存注册用户
        this.save(agentUser);

        // 验证是否是邀请用户,如果是被邀请用户，则绑定邀请用户id关系
//        if (StringUtil.isNotBlank(dto.getInviteCode())) {
//            // 通过租户id + 邀请id获取用户信息
//            AgentUser agentUserInvite = this.getOne(new LambdaQueryWrapper<AgentUser>()
//                    .eq(AgentUser::getTenantId, dto.getTenantId())
//                    .eq(AgentUser::getUuId, dto.getInviteCode())
//            );
//            if (Objects.isNull(agentUserInvite)) {
//                throw new ServiceException("邀请用户不存在!");
//            }
//
//            // 通过租户id+邀请id找到销售id
//            DistributionAssociationRecord associationRecord = distributionAssociationRecordService.getBaseMapper().selectOne(new LambdaQueryWrapper<DistributionAssociationRecord>()
//                    .eq(DistributionAssociationRecord::getTenantId, dto.getTenantId())
//                    .eq(DistributionAssociationRecord::getUserId, agentUserInvite.getId())
//                    .eq(DistributionAssociationRecord::getIsDeleted, 0)
//            );
//            if (Objects.isNull(associationRecord)) {
//                throw new ServiceException("邀请用户的邀请关系不存在!");
//            }
//
//            // 保存注册用户
//            this.save(agentUser);
//
//            // 保存用户邀请记录
//            AgentUserInvite invite = new AgentUserInvite();
//            invite.setTenantId(dto.getTenantId());
//            invite.setInviteType(1);
//            invite.setUserId(agentUser.getId());
//            invite.setInviteCode(dto.getInviteCode());
//            invite.setInviteUserId(agentUserInvite.getId());
//            iAgentUserInviteService.save(invite);
//
//            // 保存用户邀请上下级关联关系表
//            DistributionAssociationRecord record = new DistributionAssociationRecord();
//            record.setTenantId(dto.getTenantId());
//            record.setUserId(agentUser.getId());
//            record.setCurrentParentId(agentUserInvite.getId());
//            record.setSalesUserId(associationRecord.getSalesUserId());
//            distributionAssociationRecordService.save(record);
//
//        } else {
//            // 普通用户注册，保存用户邀请上下级关联关系表
//            if (StringUtil.isEmpty(dto.getSalesUserId())) {
//                throw new ServiceException("销售id不能为空!");
//            }
//            Long salesUserId = Long.parseLong(dto.getSalesUserId().replace("_TT", ""));
//
//            // 根据租户id+销售用户id检查b端用户角色是否是销售员
//            boolean roleExists = roleMapper.checkUserWithSalesRoleExists(dto.getTenantId(), salesUserId);
//            if (!roleExists) {
//                throw new ServiceException("销售用户不存在!");
//            }
//
//            // 保存注册用户
//            this.save(agentUser);
//
//            // 保存用户邀请记录
//            AgentUserInvite invite = new AgentUserInvite();
//            invite.setTenantId(dto.getTenantId());
//            invite.setInviteType(0);
//            invite.setUserId(agentUser.getId());
//            invite.setInviteUserId(salesUserId);
//            iAgentUserInviteService.save(invite);
//
//            // 保存上下级关系
//            DistributionAssociationRecord record = new DistributionAssociationRecord();
//            record.setTenantId(dto.getTenantId());
//            record.setUserId(agentUser.getId());
//            record.setSalesUserId(salesUserId);
//            distributionAssociationRecordService.save(record);
//        }

        // 返回用户登录信息
        UserInfo userInfo = new UserInfo();
        userInfo.setAgentUser(agentUser);
        // 根据每个用户平台，建立对应的detail表，通过查询将结果集写入到detail字段
        Kv detail = Kv.create().set("type", UserEnum.OTHER.getName());
        userInfo.setDetail(detail);

        Kv kv = TokenUtil.createAuthInfo(userInfo);
        return kv;
    }

    /**
     * 获取uuid
     * @return String
     */
    private String getUuid() {
        String uuid;
        do {
            uuid = this.generateUUID();
        } while (this.isUuidExist(uuid));
        return uuid;
    }

    private String generateUUID() {
        StringBuilder code = new StringBuilder(new SimpleDateFormat("yyyyMMdd").format(new Date()));
        Random random = new Random();
        for (int i = 0; i < 6; i++) {
            code.append(random.nextInt(10));
        }
        return code.toString();
    }

    private boolean isUuidExist(String uuid) {
        // 检查uuid是否存在
        AgentUser agentUser = new AgentUser();
        agentUser.setUuId(uuid);
        Integer integer = Math.toIntExact(baseMapper.selectCount(Condition.getQueryWrapper(agentUser)));
        if (integer > 0) {
            return true;
        }
        return false;
    }

    @Override
    public boolean userRetrievePass(UserRegisterDTO dto) {
        Tenant tenant = SysCache.getTenant(dto.getTenantId());
        if (tenant == null || tenant.getId() == null) {
            throw new ServiceException("租户信息错误!");
        }
        // 验证两次密码是否正确
        if (!dto.getFisPassword().equals(dto.getSecPassword())) {
            throw new ServiceException("两次密码不一致!");
        }
        // 验证验证码是否正确
        SmsCode smsCode = new SmsCode();
        smsCode.setId(dto.getSmsKey());
        smsCode.setPhone(dto.getUserPhone());
        smsCode.setValue(dto.getSmsValue());
        // 短信验证默认通过，等短信开通后配合短信发送一起放开
        boolean valid = aliSmsTemplate.validateMessage(smsCode);
        if (!valid) {
            throw new ServiceException("短信验证码错误");
        }
        // 更新用户信息
        AgentUser agentUser = this.getOne(Wrappers.<AgentUser>query().lambda().eq(AgentUser::getUserPhone, dto.getUserPhone()).eq(AgentUser::getTenantId, dto.getTenantId()));
        if (Objects.isNull(agentUser)) {
            throw new ServiceException("用户不存在");
        }
        agentUser.setPassword(DigestUtil.hex(dto.getFisPassword()));

        return this.updateById(agentUser);
    }

    @Override
    public boolean changePassword(UserChangePasswordDTO dto) {
        AgentUser agentUser = this.getOne(Wrappers.<AgentUser>query().lambda()
                .eq(AgentUser::getId, AuthUtil.getUserId())
                .eq(AgentUser::getTenantId, AuthUtil.getTenantId())
                .eq(AgentUser::getIsDeleted, 0)
        );
        if (Objects.isNull(agentUser)) {
            throw new ServiceException("用户不存在!");
        }
        // 判断原密码和数据库原密码是否一致
        if (!DigestUtil.hex(dto.getOldPassword()).equals(agentUser.getPassword())) {
            throw new ServiceException("原密码不一致，请重新输入!");
        }
        // 验证两次密码是否正确
        if (!dto.getFisPassword().equals(dto.getSecPassword())) {
            throw new ServiceException("两次密码不一致!");
        }
        agentUser.setPassword(DigestUtil.hex(dto.getFisPassword()));

        return this.updateById(agentUser);
    }

    @Override
    public boolean realNameAuth(UserRealNameAuthDTO dto) {
        String tenantId = AuthUtil.getTenantId();
        AgentUser search = new AgentUser();
        search.setTenantId(tenantId);
        search.setId(AuthUtil.getUserId());
        AgentUser agentUser = baseMapper.selectOne(Condition.getQueryWrapper(search));
        Assert.notNull(agentUser, "用户不存在");

        // 验证身份证是否合法
        boolean authenticate = idCardAuthComponent.authenticate(AliIdCardAuthServiceImpl.class.getSimpleName(), dto.getUserName(), dto.getIdentityCardNumber());
        if (!authenticate) {
            throw new ServiceException("身份验证错误!");
        }

        // 设置实名状态
        agentUser.setUserName(dto.getUserName());
        agentUser.setRealNameState(1);
        agentUser.setIdentityCardNumber(dto.getIdentityCardNumber());
        agentUser.setRealNameTime(new Date());
        baseMapper.updateById(agentUser);

        return true;
    }

    @Override
    public boolean assistOpening(UserAssistOpeningDTO dto) {

        AgentUser check = this.getOne(Wrappers.<AgentUser>query().lambda()
                .eq(AgentUser::getTenantId, AuthUtil.getTenantId())
                .eq(AgentUser::getUserType, 2)
                .eq(AgentUser::getUserPhone, dto.getUserPhone())
                .eq(AgentUser::getIsDeleted, 0)
        );
        if (Objects.nonNull(check)) {
            throw new ServiceException("用户已存在!");
        }

        // 验证两次密码是否正确
        if (!dto.getFisPassword().equals(dto.getSecPassword())) {
            throw new ServiceException("两次密码不一致!");
        }

        AgentUser agentUser = BeanUtil.toBean(dto, AgentUser.class);
        agentUser.setPassword(DigestUtil.hex(dto.getFisPassword()));
        agentUser.setUserType(2);
        agentUser.setUuId(this.getUuid());
        agentUser.setAccount(dto.getUserPhone());
        agentUser.setUserName(dto.getUserPhone());
        agentUser.setRealNameState(0);
        agentUser.setMemberState(0);
        agentUser.setFollowState(0);
        agentUser.setEnableState(1);
        agentUser.setRecentLoginTime(cn.hutool.core.date.DateUtil.date());
        agentUser.setCreateTime(cn.hutool.core.date.DateUtil.date());
        agentUser.setUpdateTime(cn.hutool.core.date.DateUtil.date());
        agentUser.setIsDeleted(0);
        // 保存注册用户
        this.save(agentUser);

        // 获取当前登录用户的销售id
//        DistributionAssociationRecord current = distributionAssociationRecordService.getBaseMapper().selectOne(new LambdaQueryWrapper<DistributionAssociationRecord>()
//                .eq(DistributionAssociationRecord::getTenantId, AuthUtil.getTenantId())
//                .eq(DistributionAssociationRecord::getUserId, AuthUtil.getUserId())
//                .eq(DistributionAssociationRecord::getIsDeleted, 0)
//        );
//        if (Objects.isNull(current)) {
//            throw new ServiceException("您上下级关系不存在!请联系管理员。");
//        }
//        if (StringUtil.isEmpty(current.getSalesUserId())) {
//            throw new ServiceException("您的销售id不能为空!请联系管理员。");
//        }
//
//        // 保存邀请记录
//        AgentUserInvite invite = new AgentUserInvite();
//        invite.setTenantId(AuthUtil.getTenantId());
//        invite.setInviteType(2);
//        invite.setUserId(agentUser.getId());
//        invite.setInviteUserId(AuthUtil.getUserId());
//        iAgentUserInviteService.save(invite);
//
//        // 保存用户邀请上下级关联关系表
//        DistributionAssociationRecord record = new DistributionAssociationRecord();
//        record.setTenantId(AuthUtil.getTenantId());
//        record.setUserId(agentUser.getId());
//        record.setCurrentParentId(AuthUtil.getUserId());
//        // 把上级的销售id找出来赋值给当前被邀请用户
//        record.setSalesUserId(current.getSalesUserId());
//        distributionAssociationRecordService.save(record);

        return true;
    }

    @Override
    public boolean userEdit(UserEditDTO dto) {
        Long userId = AuthUtil.getUserId();
        String tenantId = AuthUtil.getTenantId();
        AgentUser selectOne = baseMapper.selectOne(new LambdaQueryWrapper<AgentUser>()
                .eq(AgentUser::getId, userId)
                .eq(AgentUser::getTenantId, tenantId)
                .eq(AgentUser::getIsDeleted, 0)
        );
        if (Objects.isNull(selectOne)) {
            throw new ServiceException("用户不存在!");
        }

        // 用户名不为空，设置用户
        if (StringUtil.isNotBlank(dto.getUserName())) {
            selectOne.setUserName(dto.getUserName());
        }

        // 微信号不为空，设置微信号
        if (StringUtil.isNotBlank(dto.getWechatAccount())) {
            selectOne.setWechatAccount(dto.getWechatAccount());
        }
        this.updateById(selectOne);

        return true;
    }

    @Override
    public AgentUserInfoDTO getCurrentUserInfo() {
        AgentUser agentUser = baseMapper.selectOne(new LambdaQueryWrapper<AgentUser>()
                .eq(AgentUser::getTenantId, AuthUtil.getTenantId())
                .eq(AgentUser::getId, AuthUtil.getUserId())
        );
        if (Objects.isNull(agentUser)) {
            throw new ServiceException("用户不存在!");
        }
        AgentUserInfoDTO agentUserInfoDTO = BeanUtil.toBean(agentUser, AgentUserInfoDTO.class);
        if (StringUtil.isNotBlank(agentUserInfoDTO.getUserName())) {
            agentUserInfoDTO.setDzUserName(DataMaskingUtil.maskName(agentUserInfoDTO.getUserName()));
        }
        if (StringUtil.isNotBlank(agentUserInfoDTO.getUserPhone())) {
            agentUserInfoDTO.setDzUserPhone(DataMaskingUtil.maskPhoneNumber(agentUserInfoDTO.getUserPhone()));
        }
        if (StringUtil.isNotBlank(agentUserInfoDTO.getIdentityCardNumber())) {
            agentUserInfoDTO.setDzIdentityCardNumber(DataMaskingUtil.maskIdCard(agentUserInfoDTO.getIdentityCardNumber()));
        }

        // 用户微信是否绑定
        if (StringUtil.isNotBlank(agentUser.getOpenId())) {
            agentUserInfoDTO.setIsBind(Boolean.TRUE);
        } else {
            agentUserInfoDTO.setIsBind(Boolean.FALSE);
        }

        return agentUserInfoDTO;
    }
}
